
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <glib.h>
#include <math.h>
#include <json-glib/json-glib.h>
#include <json-glib/json-gobject.h>
#include <gio/gio.h>
#include "gts.h"
#include "communication.h"

#include "gz.h"
#define DB_NAME 	"ts-3.1.0.db"
#define SOFTWARE_NAME 	"ftp"
/*
void *mutation_device(void *user_data)
{
  TsDevice *device = NULL;
  TsInterface *interface = NULL;
  TsPoint *point = NULL, *next = NULL, *p = NULL;
  char *str = NULL, *value = NULL;
  gpointer root = NULL, inner = NULL;

  device = user_data;
  g_object_get(device, "son", &interface, NULL);
  g_object_get(interface, "son", &point, NULL);
  while (point) {
    g_object_get(point, "next", &next, "value", &value, NULL);
    if (value) {
      if (!root)
        root = protocol_init_from_point(p, 1, &inner);
      protocol_encode(inner, p, TRUE, filename, 0);
      free(value);
    }
    point = next;
  }
  if (root) {
    str = node_to_string(root);
    node_unref(root, NULL);
  }
  return str;
}
*/
void *ftp_run(void *user_data)
{
  TsSoftware *software = NULL;
  TsDevice *device = NULL;
  gpointer mqtt = NULL;
  gint64 tm0 = 0, tm1 = 0;
  char topic[1024], *str = NULL;

  device = user_data;
  g_object_get(device, "parent", &software, NULL);
  g_object_get(software, "intra", &mqtt, NULL);
  g_snprintf(topic, sizeof(topic), "3.1.2/%s/all/33/mutation", g_get_prgname());
  tm0 = g_get_real_time()/(1000*1000);
	while (1) {
    tm1 = g_get_real_time()/(1000*1000);
    if ((tm1 < tm0) || ((tm1 - tm0) > 1)) {
      tm0 = tm1;
      //str = mutation_device(user_data);
      if (str) {
        mqtt_send(mqtt, str, strlen(str), topic);
        free(str);
      }
    }
		sleep(1);
	}
}
void *mutation_310_to_313(const char *payload, char **send_topic_p,
    const char *type, void *user_data)
{
  TsSoftware *read_sfw = NULL, *software = NULL;
  TsDevice *read_dev = NULL;
  TsInterface *read_ifa = NULL;
  TsPoint *read_pit = NULL, *pit_next = NULL;
  gchar *str = NULL;

  read_sfw = protocol_decode(payload, 1);
  g_object_get(read_sfw, "son", &read_dev, NULL);
  g_object_get(read_dev, "son", &read_ifa, NULL);
  g_object_get(read_ifa, "son", &read_pit, NULL);

  JsonNode *send_node = NULL;
  JsonObject *send_obj = NULL;
  JsonArray *send_array = NULL;
  char *value = NULL;
  const char *obj_str = NULL;
  GError *error = NULL;

  software = user_data;
  obj_str = g_object_get_data(G_OBJECT(software), "point_id");
  if (!obj_str) {
    g_warning("%p no param", software);
    return NULL;
  }
  send_obj = json_object_new();
  send_node = json_node_init_object(json_node_alloc(), send_obj);
  obj_str = g_object_get_data(G_OBJECT(software), "point_id");
  json_object_set_int_member(send_obj, "pointId", GPOINTER_TO_INT(obj_str));
  obj_str = g_object_get_data(G_OBJECT(software), "station_id");
  json_object_set_int_member(send_obj, "stationId", GPOINTER_TO_INT(obj_str));
  json_object_set_string_member(send_obj, "type", type);
  send_array = json_array_new();
  json_object_set_array_member(send_obj, "fileNameList", send_array);
  obj_str = g_object_get_data(G_OBJECT(software), "path");
  char *time_str = NULL;
  GDateTime *dt = NULL;
  GDateTime *ndt = NULL;
  dt = g_date_time_new_now_utc();
  ndt = g_date_time_add_hours(dt, 8);
  time_str = g_date_time_format(ndt, "%Y-%m-%dT%H:%M:%SZ");
  if (dt)
     g_date_time_unref(dt);
  if (ndt)
     g_date_time_unref(ndt);
  json_object_set_string_member(send_obj, "time", time_str);


  while (read_pit) {
    g_object_get(read_pit, "next", &pit_next, "value", &value, NULL);
    if (value) {
      char dst[1024] = {0}, *base = NULL;
      base = g_path_get_basename(value);
      g_snprintf(dst, sizeof(dst), "%s%s", obj_str, base);
      g_free(base);
      GFile *source_file = g_file_new_for_path(value);
      GFile *dest_file = g_file_new_for_path(dst);
      gboolean result = g_file_copy(source_file, dest_file, G_FILE_COPY_NONE,
          NULL, NULL, NULL, &error);
      if (!result) {
          g_print("Error copying file: %s\n", error->message);
          g_error_free(error);
          return NULL;
      }
      g_object_unref(source_file);
      g_object_unref(dest_file);

      json_array_add_string_element(send_array, dst);
      g_free(value);
    }
    read_pit = pit_next;
  }

  str = json_to_string(send_node, FALSE);
  if (str) {
    *send_topic_p = g_strdup("3.1.3/collectors/all/2/mutation");
  }
  if (send_node)
    json_node_free(send_node);
  if (read_sfw)
    g_object_unref(read_sfw);
  return str;
}
void *param_handle(const char *payload, void *user_data)
{
  JsonNode *node = NULL;
  JsonObject *object = NULL;
  GError *error = NULL;

  node = json_from_string(payload, &error);
  if (error) {
    g_warning("L%d f-%s err:%s", __LINE__, __func__, error->message);
    return NULL;
  }
  object = json_node_get_object(node);
  TsSoftware *software = NULL;
  const char *obj_str;
  int int32;

  software = user_data;
  obj_str = json_object_get_string_member(object, "path");
  g_object_set_data(G_OBJECT(software), "path", g_strdup(obj_str));
  int32 = json_object_get_int_member(object, "pointId");
  g_object_set_data(G_OBJECT(software), "point_id", GINT_TO_POINTER(int32));
  int32 = json_object_get_int_member(object, "stationId");
  g_object_set_data(G_OBJECT(software), "station_id", GINT_TO_POINTER(int32));

  if (node)
    json_node_unref(node);
  return NULL;
}
static void mqtt_connect_callback(void *p, void *user_data, int code)
{
  char topic[1024] = {0};
  g_debug("L%d f-%s connect:\n", __LINE__, __func__);

  g_snprintf(topic, sizeof(topic), "3.1.3/+/collectors/+/param");
  mqtt_subscribe(p, topic, NULL);
  g_debug("subscribe topic: %s ", topic);

  g_snprintf(topic, sizeof(topic), "3.1.2/+/all/+/mutation");
  mqtt_subscribe(p, topic, NULL);
  g_debug("subscribe topic: %s ", topic);

  g_snprintf(topic, sizeof(topic), "3.1.3/+/pushs/+/result");
  mqtt_subscribe(p, topic, NULL);
  g_debug("subscribe topic: %s ", topic);
  return;
}
void *mqtt_result_handle(const char *payload, char **topic_p, void *user_data)
{
  gz_device_model("/var/www/html/handheldWorkOrder/sqllite/handorder.db",
      "c_point", "ts/result/ftp/point_model.xml");

  void *doc = NULL, *node = NULL;
  char *res = NULL;
  doc = gz_init("Client01", "Server01", "161", "1", &node);
  gz_node_add_path(node, "point_model.xml");
  res = gz_dump(doc);
  g_debug("res:%s", res);
  g_free(res);

  doc = gz_init("Client01", "Server01", "161", "1", &node);
  gz_node_add_value(node, "1111", "1", "test", "point_model.xml");
  res = gz_dump(doc);
  g_debug("res:%s", res);
  g_free(res);

  //JsonNode *node = NULL;
  JsonObject *obj = NULL;
  //JsonArray *array = NULL;
  char *str = NULL;
  const char *obj_str = NULL;
  //GError *error = NULL;

  obj = json_object_new();
  node = json_node_init_object(json_node_alloc(), obj);
  obj_str = g_object_get_data(G_OBJECT(user_data), "point_id");
  json_object_set_int_member(obj, "pointId", GPOINTER_TO_INT(obj_str));
  obj_str = g_object_get_data(G_OBJECT(user_data), "station_id");
  json_object_set_int_member(obj, "stationId", GPOINTER_TO_INT(obj_str));
  char *time_str = NULL;
  GDateTime *dt = NULL;
  GDateTime *ndt = NULL;
  dt = g_date_time_new_now_utc();
  ndt = g_date_time_add_hours(dt, 8);
  time_str = g_date_time_format(ndt, "%Y-%m-%dT%H:%M:%SZ");
  if (dt)
     g_date_time_unref(dt);
  if (ndt)
     g_date_time_unref(ndt);
  json_object_set_string_member(obj, "time", time_str);
  str = json_to_string(node, FALSE);
  if (str) {
    *topic_p = g_strdup("3.1.3/ftp/javaweb/2/result");
  }
  if (node)
    json_node_free(node);
  return str;
}
static void mqtt_message_callback(void *mqtt, void *user_data, void *message)
{
	char *send_topic = NULL, *str = NULL, *clientID = NULL;
	const char *topic, *payload;
  TsSoftware *software = NULL;
  TsDevice *device = NULL;
  TsInterface *interface = NULL;
  TsPoint *point = NULL;

	software = user_data;
  g_object_get(software, "son", &device, NULL);
  g_object_get(device, "son", &interface, "nameAlias", &clientID, NULL);
  g_object_get(interface, "son", &point, NULL);
  topic = mqtt_message_get_topic(message);
  payload = mqtt_message_get_payload(message);
	g_debug("L%d f-%s ++++[%s]:%s", __LINE__, __func__, topic, payload);
  if (g_str_has_suffix(topic, "param")) {
    param_handle(payload, user_data);
  } else if (g_str_has_suffix(topic, "mutation")) {
    if (g_str_has_prefix(topic, "3.1.2/mqtt")) {
      str = mutation_310_to_313(payload, &send_topic, "ir", user_data);
    } else if (g_str_has_prefix(topic, "3.1.2/tcp_server")) {
      str = mutation_310_to_313(payload, &send_topic, "pd", user_data);
    }
  } else if (g_str_has_suffix(topic, "result")) {
    str = mqtt_result_handle(payload, &send_topic, user_data);
  }
  if (str) {
    mqtt_send(mqtt, str, strlen(str), send_topic);
    g_free(str);
  }
  if (send_topic)
    g_free(send_topic);
}

int ftps_send(void)
{
  SSL_CTX *ctx;
  SSL *ssl;
  BIO *bio;

  SSL_library_init();
  OpenSSL_add_all_algorithms();
  SSL_load_error_strings();

  ctx = SSL_CTX_new(SSLv23_client_method());
  SSL_CTX_set_options(ctx, SSL_OP_ALL);
  bio = BIO_new_ssl_connect(ctx);
  BIO_set_conn_hostname(bio, "ftps://ftp.example.com:990");
  BIO_get_ssl(bio, &ssl);
  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
  if (BIO_do_connect(bio) <= 0) {
    fprintf(stderr, "Failed to connect to FTP server\n");
    ERR_print_errors_fp(stderr);
    BIO_free_all(bio);
    SSL_CTX_free(ctx);
    return -1;
  }
  if (BIO_do_handshake(bio) <= 0) {
    fprintf(stderr, "Failed to perform SSL handshake\n");
    ERR_print_errors_fp(stderr);
    BIO_free_all(bio);
    SSL_CTX_free(ctx);
    return -1;
  }
  // 发送切换目录命令
  char *upload_directory = "target_directory";
  char command[256];
  sprintf(command, "CWD %s\r\n", upload_directory);
  SSL_write(ssl, command, strlen(command));

  // 检查命令执行结果
  char response[256];
  SSL_read(ssl, response, sizeof(response));

  if (strncmp(response, "250", 3) != 0) {
      perror("Error changing directory on FTP server");
      exit(1);
  }

  char *filename = "/path/to/local/file";
  //char *remote_filename = "remote_file_name";

  FILE *fp = fopen(filename, "rb");
  if (fp == NULL) {
      perror("Error opening file");
      exit(1);
  }

  char write_buffer[1024];
  int bytes_read = 0;
  int bytes_written = 0;
  while ((bytes_read = fread(write_buffer, 1, sizeof(write_buffer), fp)) > 0) {
      bytes_written = SSL_write(ssl, write_buffer, bytes_read);
      if (bytes_written <= 0) {
          perror("Error writing file to FTP server");
          exit(1);
      }
  }

  fclose(fp);
/*
  char buffer[1024];
  int len;
  const char* command = "RETR file.txt";
  if (BIO_puts(bio, command) <= 0) {
    fprintf(stderr, "Failed to send FTP command\n");
    ERR_print_errors_fp(stderr);
    BIO_free_all(bio);
    SSL_CTX_free(ctx);
    return -1;
  }
  FILE *fp = fopen("file.txt", "wb");
  if (fp != NULL) {
    while ((len = BIO_read(bio, buffer, sizeof(buffer))) > 0) {
      fwrite(buffer, 1, len, fp);
    }
    fclose(fp);
  }
  */
  BIO_free_all(bio);
  SSL_CTX_free(ctx);

  return 0;
}
int main(int argc, char **argv)
{
  g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
  g_set_prgname(SOFTWARE_NAME);
  ftps_send();
  exit(1);

#if 0
  gz_device_model("examples/ftp/handorder.db", "c_point",
      "examples/ftp/point_model.xml");

  void *doc = NULL, *node = NULL;
  char *res = NULL;
  doc = gz_init("Client01", "Server01", "161", "1", &node);
  gz_node_add_path(node, "point_model.xml");
  res = gz_dump(doc);
  g_debug("res:%s", res);

  doc = gz_init("Client01", "Server01", "161", "1", &node);
  gz_node_add_value(node, "1111", "1", "test", "point_model.xml");
  res = gz_dump(doc);
  g_debug("res:%s", res);
#endif
  gint rc = 0;
  TsSoftware *software = NULL, *data = NULL;
  TsDevice *device = NULL, *device_next = NULL;
  gchar *id_str = NULL;
  gpointer mqtt = NULL;

  data = local_data(DB_NAME);
  software = config_from_db(DB_NAME, g_get_prgname());
  config_reset_status(software, FALSE);
  local_point_signal_connect(software, data);
  g_object_get(software, "son", &device, NULL);

  mqtt = mqtt_init(NULL, NULL, NULL, software);
  mqtt_set_connect_callback(mqtt, mqtt_connect_callback, NULL);
  mqtt_set_message_callback(mqtt, mqtt_message_callback, NULL);
  mqtt_run(mqtt, "0.0.0.0", 1883);

  while (device) {
    sleep(1);
    g_object_get(device, "next", &device_next, NULL);
    GThread *thread;
		thread = g_thread_new(id_str, ftp_run, device);
    g_thread_unref(thread);
    device = device_next;
  }
  g_main_loop_run(g_main_loop_new(NULL, FALSE));

	return rc;
}
